using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using FireStarter.Base;
using FireStarter.CodeGeneration.Generator;
using FireStarter.CodeGeneration.Parser;
using FireStarterModeller.BO;

namespace FireStarterModeller.Logic
{
    //TODO Eric 31 Aug 2009: There are two almost identical templates being used
    // between this and the DMToEntityClassDefsXmlConverter.  Need to merge so sections of the
    // templates are not duplicated.
    // NOTE: the non "Parameter_Type" templates are the right ones for normal ClassDef generation
    public class DMToClassDefsXmlConverter : IDMToClassDefsXmlConverter
    {

        public string ConvertToXml(DMSolution solution)
        {
            return ConvertToXml((IModelElement) solution);
        }

        public string ConvertToXml(DMClass dmClass)
        {
            return ConvertToXml((IModelElement)dmClass);
        }

        public string ConvertToXml(IModelElement element)
        {
            string template = GetTemplate(element.GetType().Name);

            List<IActionParser> actionParsers = StatementParser.GetDefaultActionParsers();
            actionParsers.Add(new IncludeExpressionParser(new ResourceTemplateLoader(this.GetType().Assembly, "FireStarterModeller.Logic.ClassDefXmlTemplate")));

            return ConvertToXml(element, template, actionParsers);
        }

        private static string GetTemplate(string typeName)
        {
            string template;
            switch (typeName)
            {
                case "DMSolution":
                    template = ClassDefXmlTemplate.ClassDefXmlTemplateText;
                    break;
                case "DMClass":
                    template = ClassDefXmlTemplate.SingleClassDefXmlTemplateText;
                    break;
                case "UIView":
                    template = ClassDefXmlTemplate.UIViewXmlTemplateText;
                    break;
                case "UIField":
                    template = ClassDefXmlTemplate.UIFieldXmlTemplateText;
                    break;
                case "UIGridColumnInfo":
                    template = ClassDefXmlTemplate.UIGridColumnTemplateText;
                    break;
                case "UIGridInfo":
                    template = ClassDefXmlTemplate.UIGridXmlTemplateText.Replace("UIGridInfo.", ""); //ERIC - can't get around this workaround now, maybe Mark's template changes will help (you only change context when you are inside a for loop)
                    break;
                case "UIFormInfo":
                    template = ClassDefXmlTemplate.UIFormXmlTemplateText.Replace("UIFormInfo.", "");
                    break;
                case "UIGridFilter":
                    template = ClassDefXmlTemplate.UIGridFilterXmlTemplateText.Replace("UIGridInfo.UIGridFilter.", "");
                    break;
                case "UIGridFilterProp":
                    template = ClassDefXmlTemplate.UIGridFilterPropertyXmlTemplateText;
                    break;
                case "UITab":
                    template = ClassDefXmlTemplate.UITabXmlTemplateText;
                    break;
                case "UIColumnLayout":
                    template = ClassDefXmlTemplate.UIColumnLayoutXmlTemplateText;
                    break;
                case "UIParameter":
                    template = ClassDefXmlTemplate.UIParameterXmlTemplateText;
                    break;
                default:
                    throw new NotImplementedException("No specific template is available for " + typeName);
            }
            return template;
        }

        private static string ConvertToXml(IModelElement element, string template,  List<IActionParser> actionParsers)
        {
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());

            StatementParser statementParser = new StatementParser();
            TemplateExpression templateExpression = statementParser.Parse(ref template, actionParsers);
            string xmlForSolution = templateExpression.Generate(modelStrategyMapper, element);
            //return xmlForSolution;

            //The following is used to take the xml and output and cleaner, formatted version
            var output = new StringBuilder();
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.Indent = true;
            xmlWriterSettings.CloseOutput = true;
            xmlWriterSettings.OmitXmlDeclaration = true;
            using (XmlWriter xmlWriter = XmlWriter.Create(output, xmlWriterSettings))
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(xmlForSolution);
                xmldoc.Save(xmlWriter);
            }
            return output.ToString();
        }
    }
}